package com.tianji.learning.tasks;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.tianji.common.constants.CacheConstants;
import com.tianji.common.utils.DateUtils;
import com.tianji.learning.domain.entity.PointsBoardSeason;
import com.tianji.learning.domain.vo.PointsBoardItemVO;
import com.tianji.learning.mapper.PointsBoardMapper;
import com.tianji.learning.service.IPointsBoardSeasonService;
import com.tianji.learning.service.UserQueryService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

@Slf4j
//@Component
public class PointsBoardSyncToMysqlTask {
    private static Map<String,Object> msg=new HashMap<>();

    @Autowired
    private IPointsBoardSeasonService seasonService;
    @Autowired
    private PointsBoardMapper boardMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private UserQueryService userQueryService;

    // 每个月1号凌晨1点，把redis中的zset中的榜单数据同步到mysql
    // 秒 分 时 天 月 周
    @Scheduled(cron = "0 0 1 1 * ?")
    public void pointsBoardSyncToMysql() {
        // 根据赛季的开始时间和结束时间查询赛季的id，上一个月的开始时间和结束时间
        LocalDate localDate = LocalDateTime.now().minusMonths(1).toLocalDate();
        LocalDate begin = DateUtils.getMonthBegin(localDate);
        LocalDate end = DateUtils.getMonthEnd(localDate);
        PointsBoardSeason season = seasonService.getByDate(begin, end);
        if (season == null) {
            log.error("没有更多赛季");
            return;
        }
        // 生成mysql中的表名：points_board_${赛季的id}
        Integer id = season.getId();
        String tableName = CacheConstants.POINTS_BOARD_PREFIX + id;
        boardMapper.createTable(tableName);
        // 分页读取redis中的zset中的排行榜
        String day = LocalDateTimeUtil.format(LocalDateTime.now(), "yyyyMM");
        String key = CacheConstants.POINTS_BOARD + day;
        int pageNo = 1, pageSize = 100;
        while (true){
            int startIndex = (pageNo - 1) * pageSize;
            int endIndex = pageNo * pageSize - 1;
            Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet().reverseRangeWithScores(key, startIndex, endIndex);
            if (CollectionUtil.isEmpty(typedTuples)) {
                break;
            }
            List<PointsBoardItemVO> pointsBoardItemVOS = new ArrayList<>();
            ArrayList<ZSetOperations.TypedTuple<String>> typedTupleList = new ArrayList<>(typedTuples);
            for (int i = 0; i < typedTupleList.size(); i++) {
                PointsBoardItemVO itemVO = new PointsBoardItemVO();
                ZSetOperations.TypedTuple<String> stringTypedTuple = typedTupleList.get(i);
                Double userScore = stringTypedTuple.getScore();
                String userIdstring  = stringTypedTuple.getValue();
                itemVO.setPoints(userScore.intValue());
                itemVO.setRank(startIndex+i+1);
                itemVO.setName(userIdstring);
                itemVO.setUserId(Long.parseLong(userIdstring));
                pointsBoardItemVOS.add(itemVO);
            }
           /* // userId -> userName
            Map<Long, UserDTO> userMap =userQueryService.getUserMap(pointsBoardItemVOS);
            for (PointsBoardItemVO pointsBoardItemVO : pointsBoardItemVOS) {
                UserDTO user = userMap.get(Long.parseLong(pointsBoardItemVO.getName()));
//                pointsBoardItemVO.setName(user==null?"":user.getName());
                pointsBoardItemVO.setUserId(user==null?null:user.getId());
            }*/
            // 批量写入mysql
            boardMapper.batchInsert(tableName, pointsBoardItemVOS);
            // 下一页
            pageNo++;

        }
        // 删除redis中的榜单数据
        redisTemplate.unlink(key);
    }

    @XxlJob("createTableJob")
    public ReturnT<String> createTableJob() {
// 根据赛季的开始时间和结束时间查询赛季的id，上一个月的开始时间和结束时间
        LocalDate localDate = LocalDateTime.now().minusMonths(1).toLocalDate();
        LocalDate begin = DateUtils.getMonthBegin(localDate);
        LocalDate end = DateUtils.getMonthEnd(localDate);
        PointsBoardSeason season = seasonService.getByDate(begin, end);
        if (season == null) {
            log.error("没有更多赛季");
            XxlJobHelper.log("没有更多赛季");
            return ReturnT.FAIL;
        }
        // 生成mysql中的表名：points_board_${赛季的id}
        Integer id = season.getId();
        String tableName = CacheConstants.POINTS_BOARD_PREFIX + id;
        msg.put("tableName",tableName);
        boardMapper.createTable(tableName);
        return ReturnT.SUCCESS;
    }
    @XxlJob("savePointsBoard2DB")
    public ReturnT<String> savePointsBoard2DB() {
        String tableName = (String)msg.get("tableName");
// 分页读取redis中的zset中的排行榜
        String day = LocalDateTimeUtil.format(LocalDateTime.now(), "yyyyMM");
        String key = CacheConstants.POINTS_BOARD + day;
        msg.put("key",key);
        int pageNo = 1, pageSize = 100;
        while (true){
            int startIndex = (pageNo - 1) * pageSize;
            int endIndex = pageNo * pageSize - 1;
            Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet().reverseRangeWithScores(key, startIndex, endIndex);
            if (CollectionUtil.isEmpty(typedTuples)) {
                break;
            }
            List<PointsBoardItemVO> pointsBoardItemVOS = new ArrayList<>();
            ArrayList<ZSetOperations.TypedTuple<String>> typedTupleList = new ArrayList<>(typedTuples);
            for (int i = 0; i < typedTupleList.size(); i++) {
                PointsBoardItemVO itemVO = new PointsBoardItemVO();
                ZSetOperations.TypedTuple<String> stringTypedTuple = typedTupleList.get(i);
                Double userScore = stringTypedTuple.getScore();
                String userIdstring  = stringTypedTuple.getValue();
                itemVO.setPoints(userScore.intValue());
                itemVO.setRank(startIndex+i+1);
                itemVO.setName(userIdstring);
                itemVO.setUserId(Long.parseLong(userIdstring));
                pointsBoardItemVOS.add(itemVO);
            }
           /* // userId -> userName
            Map<Long, UserDTO> userMap =userQueryService.getUserMap(pointsBoardItemVOS);
            for (PointsBoardItemVO pointsBoardItemVO : pointsBoardItemVOS) {
                UserDTO user = userMap.get(Long.parseLong(pointsBoardItemVO.getName()));
//                pointsBoardItemVO.setName(user==null?"":user.getName());
                pointsBoardItemVO.setUserId(user==null?null:user.getId());
            }*/
            // 批量写入mysql
            boardMapper.batchInsert(tableName, pointsBoardItemVOS);
            // 下一页
            pageNo++;

        }
        return ReturnT.SUCCESS;
    }
    @XxlJob("clearPointsBoardFromRedis")
    public ReturnT<String> clearPointsBoardFromRedis() {
        String key = (String)msg.get("key");
        redisTemplate.unlink(key);
        msg=new HashMap<>();
        return ReturnT.SUCCESS;
    }
}